package com.company.nuwa.common.utils;

import cn.hutool.core.util.ObjectUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import com.company.nuwa.common.constants.JwtConstants;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.Random;

/**
 * <p>jwt工具类</p>
 *
 * @author Lionel Lee
 * @version 1.0: JwtUtils.java
 * @date 2021/5/5 11:52 上午
 */
@Slf4j
public class JwtUtils {

    /**
     * 创建jwt，关键数据放在 claimMap 中
     * <p>
     *
     * @param uid       用户id
     * @param subject
     * @param isRefresh
     * @param userClaim
     * @return
     */
    public static String createJWT(Long uid, String subject, boolean isRefresh, String userClaim) {
        long ttl = isRefresh
                ? JwtConstants.JWT_DEFAULT_REFRESH_TOKEN_TTL
                : JwtConstants.JWT_DEFAULT_TTL;
        return createJWT(String.valueOf(uid), subject, ttl, userClaim);
    }

    /**
     * 创建jwt，关键数据放在 claimMap 中
     * <p>
     *
     * @param audience
     * @param subject
     * @param ttl
     * @param userClaim
     * @return
     */
    public static String createJWT(String audience, String subject, Long ttl, String userClaim) {
        Algorithm algorithm = Algorithm.HMAC256(JwtConstants.JWT_SECRET);
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        long expireAt = nowMillis + ttl;
        Date date = new Date(expireAt);
        JWTCreator.Builder builder = JWT.create()
                .withIssuedAt(now)
                .withAudience(audience)
                .withSubject(subject).withClaim("randomValue", new Random().nextInt(10000))
                .withIssuer(JwtConstants.JWT_ISSUER)
                .withExpiresAt(date);
        if (ObjectUtil.isNotNull(userClaim)) {
            builder.withClaim(JwtConstants.USER_RESPONSE, userClaim);
        }
        return builder.sign(algorithm);
    }

    /**
     * 验证jwt
     *
     * @param token jwt
     * @return DecodedJWT
     */
    public static DecodedJWT verifyJWT(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            Algorithm algorithm = Algorithm.HMAC256(JwtConstants.JWT_SECRET);
            Verification jwtVerifier = JWT.require(algorithm)
                .withAudience(jwt.getAudience().stream().findFirst().orElse(""))
                .withSubject(jwt.getSubject()).withIssuer(jwt.getIssuer())
                .acceptExpiresAt(jwt.getExpiresAt().getTime());
            return jwtVerifier.build().verify(jwt);
        } catch (RuntimeException e) {
            throw new RuntimeException("鉴权失败，access Token过期");
        }
    }

    /**
     * 获取存储的 Audience
     *
     * @param token jwt
     * @return String
     */
    public static String getAudience(String token) {
        return verifyJWT(token).getAudience().stream().findFirst().orElse("");
    }

    /**
     * 获取存储的 Subject
     *
     * @param token jwt
     * @return String
     */
    public static String getSubject(String token) {
        return verifyJWT(token).getSubject();
    }

    /**
     * 获取存储的UserResponse
     *
     * @param token jwt
     * @return String
     */
    public static String getUserClain(String token) {
        Claim claim = verifyJWT(token).getClaims().get(JwtConstants.USER_RESPONSE);
        if (ObjectUtil.isNull(claim)) {
            return null;
        }
        return claim.asString();
    }

    /**
     * 判断token是否过期
     *
     * @param token jwt
     * @return boolean
     */
    public static boolean isTokenExpired(String token) {
        return verifyJWT(token).getExpiresAt().before(new Date());
    }

}
